package com.jobson.model.Transcation;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;

import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.beanutils.PropertyUtilsBean;

@Stateless
public abstract class DBTranscation<T> implements Serializable{

    /**
	 * 
	 */
	private static final long serialVersionUID = -460498782658961191L;
	
	private final Class<T> type1;

    // https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.java.programmer/byy0ruRCUzc
    public DBTranscation(Class<T> type) {
        this.type1 = type;
    }

    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    protected EntityManager entityManager;

    public T findById(Integer id) throws Exception {
        try {
            return entityManager.find(type1, id);
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    public Boolean save(T aObject) throws Exception {
        try {
            this.entityManager.persist(aObject);
            ;
            return true;
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    public Boolean update(T aObject) throws Exception {
        try {
            this.entityManager.merge(aObject);
            return true;
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    public Boolean delete(T aObject) throws Exception {
        try {
            this.entityManager.remove(aObject);
            this.entityManager.flush();
            return true;
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    @SuppressWarnings("rawtypes")
    protected List getLikeList(String aTable, String aColumn, String aLike, String aWhere) {

        List list = entityManager.createQuery(
                "select DISTINCT table." + aColumn + " from " + aTable + " table WHERE table." + aWhere + " LIKE '" + aLike + "%'").getResultList();
        return list;

    }

    @SuppressWarnings("unchecked")
    protected List<T> getLikeList(String aTable, String aLike, String aWhere) {
        if (null == entityManager) {
            System.out.println(" entity manager is null ---------->");
        }
        List<T> list = entityManager.createQuery("select from " + aTable + " table WHERE table." + aWhere + " LIKE '" + aLike + "%'").getResultList();
        return list;

    }

    protected List<String> getDifference(T aOldObject, T aNewObject, String aModifiedBy) throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        SimpleDateFormat date = new SimpleDateFormat("E dd-MM-yyyy 'at' hh:mm");
        String timestamp = date.format(new Date());

        List<String> changes = new ArrayList<String>();
        BeanMap map = new BeanMap(aOldObject);

        PropertyUtilsBean propUtils = new PropertyUtilsBean();

        for (Object propNameObject : map.keySet()) {

            String propertyName = (String) propNameObject;
            Object oldValue = propUtils.getProperty(aOldObject, propertyName);
            Object newValue = propUtils.getProperty(aNewObject, propertyName);
            if (null == oldValue && null == newValue) {
            } else if (null == oldValue || null == newValue) {
                if (null == oldValue || null != newValue) {
                    changes.add(formatChangeText(propertyName, oldValue, newValue, timestamp, aModifiedBy));
                } else if (null != oldValue || null == newValue) {
                    changes.add(formatChangeText(propertyName, oldValue, newValue, timestamp, aModifiedBy));
                }
            } else if (!(oldValue.equals(newValue))) {
                changes.add(formatChangeText(propertyName, oldValue, newValue, timestamp, aModifiedBy));
            }
        }
        return changes;
    }

    private String formatChangeText(String aPropertyName, Object aOldvalue, Object aNewValue, String aTimeStamp, String aModifiedBy) {
        String text = "";

        if (null == aOldvalue) {
            text = aPropertyName + " is updated to \"" + aNewValue + "\" on " + aTimeStamp.toString() + " by " + aModifiedBy;
        } else if (null == aNewValue) {
            text = aPropertyName + " is removed from \"" + aOldvalue + "\" " + aTimeStamp.toString() + " by " + aModifiedBy;
        } else {
            text = aPropertyName + " is changed from \"" + aOldvalue + "\" to \"" + aNewValue + "\" on " + aTimeStamp + " by " + aModifiedBy;
        }
        return text;
    }

    public abstract Boolean addToHistory(T aObject) throws Exception;

}
